package com.example.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.bean.Order;
import com.example.bean.OrderItem;
import com.example.bean.Product;
import com.example.bean.User;
import com.example.feign.ProductService;
import com.example.feign.UserService;
import com.example.order.mapper.OrderItemMapper;
import com.example.order.mapper.OrderMapper;
import com.example.order.service.OrderService;
import com.example.params.OrderParams;
import com.example.shoputils.constants.HttpCode;
import com.example.shoputils.resp.Result;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * @Author 刘武贵
 * @Date 2024-03-13 23:27
 * @Description 功能描述：重现分布式事务问题
 */
@Slf4j
@Service("orderServiceV8")
public class OrderServiceV8Impl implements OrderService {

    /**
     * 订单Mapper
     */
    @Resource
    private OrderMapper orderMapper;

    /**
     * 订单条目Mapper
     */
    @Resource
    private OrderItemMapper orderItemMapper;

    /**
     * 调用用户微服务的接口（feign调用）
     */
    @Resource
    private UserService userService;

    /**
     * 调用商品微服务的接口（feign调用）
     */
    @Resource
    private ProductService productService;

    /**
     * 通过@Resource注解注入RocketMQTemplate实例。
     * 该实例用于通过RocketMQ发送消息。
     */
    @Resource
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 保存订单信息
     * @param orderParams 订单参数，包含用户ID、商品ID、购买数量等信息
     * @throws RuntimeException 当参数异常、未获取到用户信息、未获取到商品信息、商品库存不足时抛出异常
     */
    @Override
    @GlobalTransactional
    public void saveOrder(OrderParams orderParams) {
        // 检查订单参数是否为空
        if (orderParams.isEmpty()){
            throw new RuntimeException("参数异常: " + JSONObject.toJSONString(orderParams));
        }

        // 获取用户信息，并校验
        User user = userService.getUser(orderParams.getUserId());
        if (user == null){
            throw new RuntimeException("未获取到用户信息: " + JSONObject.toJSONString(orderParams));
        }
        if (user.getId() == -1){
            throw new RuntimeException("触发了用户微服务的容错逻辑: " + JSONObject.toJSONString(orderParams));
        }
        // 获取商品信息，并校验
        Product product = productService.getProduct(orderParams.getProductId());
        if (product == null){
            throw new RuntimeException("未获取到商品信息: " + JSONObject.toJSONString(orderParams));
        }
        if (product.getId() == -1){
            throw new RuntimeException("触发了商品微服务的容错逻辑: " + JSONObject.toJSONString(orderParams));
        }

        // 检查商品库存是否充足
        if (product.getProStock() < orderParams.getCount()){
            throw new RuntimeException("商品库存不足: " + JSONObject.toJSONString(orderParams));
        }

        // 创建订单，并保存到数据库
        Order order = new Order();
        order.setAddress(user.getAddress());
        order.setPhone(user.getPhone());
        order.setUserId(user.getId());
        order.setUsername(user.getUsername());
        order.setTotalPrice(product.getProPrice().multiply(BigDecimal.valueOf(orderParams.getCount())));
        orderMapper.insert(order);

        // 创建订单项，并保存到数据库
        OrderItem orderItem = new OrderItem();
        orderItem.setNumber(orderParams.getCount());
        orderItem.setOrderId(order.getId());
        orderItem.setProId(product.getId());
        orderItem.setProName(product.getProName());
        orderItem.setProPrice(product.getProPrice());
        orderItemMapper.insert(orderItem);

        // 更新商品库存，并处理异常
        Result<Integer> result = productService.updateCount(orderParams.getProductId(), orderParams.getCount());
        if (result.getCode() == 1001){
            throw new RuntimeException("触发了商品微服务的容错逻辑: " + JSONObject.toJSONString(orderParams));
        }
        if (result.getCode() != HttpCode.SUCCESS){
            throw new RuntimeException("库存扣减失败");
        }
        log.info("库存扣减成功");

        int i= 1 / 0;

        /**
         * 向指定的主题发送消息。
         * 这个方法会将给定的订单对象序列化后发送到消息队列中，用于订单处理。
         *
         * @param "order-topic" 主题名称，订单消息将发送到这个主题。
         * @param order 需要发送的订单对象。
         *
         * @return 无返回值。
         */
        rocketMQTemplate.convertAndSend("order-topic", order);
    }
}

